package com.joysuch.wwyt.risk.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.joysuch.wwyt.core.enums.DeleteFlag;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.risk.entity.RiskMeasureType;
import com.joysuch.wwyt.risk.entity.vo.RiskMeasureTypeNode;
import com.joysuch.wwyt.risk.mapper.RiskMeasureTypeMapper;
import com.joysuch.wwyt.risk.repository.RiskPointEvaluationDetailDao;
import com.joysuch.wwyt.risk.service.RiskMeasureTypeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author heqifeng
 * @since 2021-09-10
 */
@Service
public class RiskMeasureTypeServiceImpl extends ServiceImpl<RiskMeasureTypeMapper, RiskMeasureType> implements RiskMeasureTypeService {

    @Autowired
    RiskMeasureTypeMapper riskMeasureTypeMapper;
    @Autowired
    private RiskPointEvaluationDetailDao riskPointEvaluationDetailDao;

    @Override
    public List<RiskMeasureTypeNode> getAllTopTypes() {
        String orgCode = Context.getCompanyCode();
        Long tenentId = Context.getCurrentTenantId();
        List<RiskMeasureType> topTypes = riskMeasureTypeMapper.getTopTypes(orgCode, tenentId);
        topTypes.sort(Comparator.comparing(RiskMeasureType::getSort));
        // 提前获取所有风险点下最新一次评估的id，用于统计措施类型是否已使用
        List<Long> lastEvaluationIds = riskMeasureTypeMapper.getLastEvaluationIds(Context.getCompanyCode(), Context.getCurrentTenantId());
        return topTypes.stream().map(each -> convertToVo(each, lastEvaluationIds)).collect(Collectors.toList());
    }

    @Override
    public List<RiskMeasureTypeNode> getAllChilds(Long id) {
        List<RiskMeasureTypeNode> riskMeasureTypeNodes = new ArrayList<>();
        List<Long> lastEvaluationIds = riskMeasureTypeMapper.getLastEvaluationIds(Context.getCompanyCode(), Context.getCurrentTenantId());
        buildTreeByParentId(id, riskMeasureTypeNodes, lastEvaluationIds);
        return riskMeasureTypeNodes;
    }

    private void buildTreeByParentId(Long id, List<RiskMeasureTypeNode> riskMeasureTypeNodes, List<Long> lastEvaluationIds) {
        //todo  check for top
//        if (id == null) {
//            return;
//        }
        List<RiskMeasureType> riskMeasureTypes = getByParentId(id);
        if (CollectionUtils.isEmpty(riskMeasureTypes)) {
            return;
        }
        List<RiskMeasureTypeNode> measureTypeVos = riskMeasureTypes.stream().map(each -> convertToVo(each, lastEvaluationIds))
                .sorted(Comparator.comparing(RiskMeasureTypeNode::getSort)).collect(Collectors.toList());
        riskMeasureTypeNodes.addAll(measureTypeVos);
        // 递归获取子分类
        measureTypeVos.forEach(each -> buildTreeByParentId(each.getId(), each.getChilds(), lastEvaluationIds));
    }

    @Override
    public List<RiskMeasureType> getAll() {
        LambdaQueryWrapper<RiskMeasureType> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RiskMeasureType::getDeleteFlag, DeleteFlag.EFFECTIVE.getCode());
        return riskMeasureTypeMapper.selectList(wrapper);
    }

    @Override
    public List<RiskMeasureType> getTopTypes() {
        LambdaQueryWrapper<RiskMeasureType> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RiskMeasureType::getDeleteFlag, DeleteFlag.EFFECTIVE.getCode());
        wrapper.eq(RiskMeasureType::getTypeLevel, 1);
        return riskMeasureTypeMapper.selectList(wrapper);
    }

    @Override
    public List<RiskMeasureType> getByParentId(Long parentId) {
        LambdaQueryWrapper<RiskMeasureType> wrapper = new LambdaQueryWrapper<>();
        if (parentId == null) {
            wrapper.isNull(RiskMeasureType::getParentId);
        } else {
            wrapper.eq(RiskMeasureType::getParentId, parentId);
        }

        wrapper.eq(RiskMeasureType::getDeleteFlag, DeleteFlag.EFFECTIVE.getCode());
        return riskMeasureTypeMapper.selectList(wrapper);
    }

    @Override
    public int addTopTypes(List<RiskMeasureType> measureTypes) {
        int initialSize = measureTypes.size();
        // 提交上来的数据重复性校验
        long nameCount = measureTypes.stream().map(RiskMeasureType::getMeasureTypeName).distinct().count();
        if (initialSize > nameCount) {
            return -1;
        }
        // 提交上来的数据与数据库重复(只校验新增的)
        List<String> nameList = measureTypes.stream().filter(each -> each.getId() == null).map(RiskMeasureType::getMeasureTypeName).collect(Collectors.toList());
        int sameName = 0;
        if (!CollectionUtils.isEmpty(nameList)) {
            sameName = riskMeasureTypeMapper.selectSameNameForTopType(nameList, Context.getCompanyCode(), Context.getCurrentTenantId());
        }
        if (sameName > 0) {
            return -1;
        }
        measureTypes.stream().forEach(item -> item.setTypeLevel(1));
        saveOrUpdateBatch(measureTypes);
        return initialSize;
    }

    @Override
    public int addChildTypes(List<RiskMeasureTypeNode> riskMeasureTypeNodes) {
        // 校验二级分类名称
        if (!checkSameName(riskMeasureTypeNodes)) {
            return -1;
        }
        int count = 0;
        for (RiskMeasureTypeNode riskMeasureTypeNode : riskMeasureTypeNodes) {
            // 保存二级分类
            Long secondId;
            if (riskMeasureTypeNode.getId() != null) {
                secondId = riskMeasureTypeNode.getId();
                RiskMeasureType riskMeasureType = new RiskMeasureType();
                BeanUtils.copyProperties(riskMeasureTypeNode, riskMeasureType);
                updateById(riskMeasureType);
            } else {
                RiskMeasureType riskMeasureType = new RiskMeasureType();
                BeanUtils.copyProperties(riskMeasureTypeNode, riskMeasureType);
                riskMeasureType.setTypeLevel(2);
                riskMeasureTypeMapper.insert(riskMeasureType);
                secondId = riskMeasureType.getId();
            }
            // 保存三级分类
            List<RiskMeasureTypeNode> childs = riskMeasureTypeNode.getChilds();
            // 校验三级分类名称
            if (!CollectionUtils.isEmpty(childs)) {
                if (!checkSameName(childs)) {
                    return -1;
                }
                for (RiskMeasureTypeNode child : childs) {
                    // 注意：二级分类也是新增时，无id，会导致三级分类无父id，此处需手动设置
                    child.setParentId(secondId);
                    RiskMeasureType riskMeasureType = new RiskMeasureType();
                    BeanUtils.copyProperties(child, riskMeasureType);
                    riskMeasureType.setTypeLevel(3);
                    saveOrUpdate(riskMeasureType);
                    count++;
                }
            }
        }
        return riskMeasureTypeNodes.size() + count;
    }

    // 通过id获取其父分类至（顶级分类）
    @Override
    public RiskMeasureTypeNode findAllParentsByChildId(Long id) {
        RiskMeasureTypeNode riskMeasureTypeNode = new RiskMeasureTypeNode();
        RiskMeasureTypeNode riskMeasureTypeNodeResult = buildTreeByChildId(id, riskMeasureTypeNode);
        return riskMeasureTypeNodeResult;
    }

    private RiskMeasureTypeNode buildTreeByChildId(Long id, RiskMeasureTypeNode riskMeasureTypeNode) {
        RiskMeasureType riskMeasureType = riskMeasureTypeMapper.selectById(id);
        if (riskMeasureType != null) {
            BeanUtils.copyProperties(riskMeasureType, riskMeasureTypeNode);
            if (riskMeasureTypeNode.getParentId() == null) {
                return riskMeasureTypeNode;
            }
            RiskMeasureTypeNode futureParentVo = new RiskMeasureTypeNode();
            futureParentVo.getChilds().add(riskMeasureTypeNode);
            return buildTreeByChildId(riskMeasureType.getParentId(), futureParentVo);
        } else {
            return riskMeasureTypeNode;
        }
    }

    @Override
    public Map<Long, RiskMeasureTypeNode> getAllTreeMapping(Set<Long> ids) {
        List<RiskMeasureType> allMeasureType = getAll();
        Map<Long, RiskMeasureType> allMeasureTypeMapper = allMeasureType.stream().collect(Collectors.toMap(RiskMeasureType::getId, r -> r));
        HashMap<Long, RiskMeasureTypeNode> result = new HashMap<>();
        ids.forEach(each -> {
            RiskMeasureTypeNode tree = findAllParentsByChildIdV2(each, allMeasureTypeMapper);
            result.put(each,tree);
        });
        return result;
    }

    // 获取树形结构（不查库）
    public RiskMeasureTypeNode findAllParentsByChildIdV2(Long id, Map<Long, RiskMeasureType> all) {
        RiskMeasureTypeNode riskMeasureTypeNode = new RiskMeasureTypeNode();
        RiskMeasureTypeNode riskMeasureTypeNodeResult = buildTreeByChildIdV2(id, riskMeasureTypeNode, all);
        return riskMeasureTypeNodeResult;
    }

    private RiskMeasureTypeNode buildTreeByChildIdV2(Long id, RiskMeasureTypeNode riskMeasureTypeNode, Map<Long, RiskMeasureType> all) {
        RiskMeasureType riskMeasureType = all.get(id);
        if (riskMeasureType != null) {
            BeanUtils.copyProperties(riskMeasureType, riskMeasureTypeNode);
            if (riskMeasureTypeNode.getParentId() == null) {
                return riskMeasureTypeNode;
            }
            RiskMeasureTypeNode futureParentVo = new RiskMeasureTypeNode();
            futureParentVo.getChilds().add(riskMeasureTypeNode);
            return buildTreeByChildIdV2(riskMeasureType.getParentId(), futureParentVo, all);
        } else {
            return riskMeasureTypeNode;
        }
    }


    private boolean checkSameName(List<RiskMeasureTypeNode> riskMeasureTypeNodes) {
        // deleteFlag为1的不校验
        Map<String, List<RiskMeasureTypeNode>> sameNameMap = riskMeasureTypeNodes.stream()
                .filter(each -> !DeleteFlag.DELETED.getCode().equals(each.getDeleteFlag())).collect(Collectors.groupingBy(RiskMeasureTypeNode::getMeasureTypeName));
        Iterator<String> iterator = sameNameMap.keySet().iterator();
        while (iterator.hasNext()) {
            List<RiskMeasureTypeNode> sameNameList = sameNameMap.get(iterator.next());
            if (sameNameList.size() > 1) {
                return false;
            }
        }
        return true;
    }

    private RiskMeasureTypeNode convertToVo(RiskMeasureType measureType, List<Long> lastEvaluationIds) {
        RiskMeasureTypeNode riskMeasureTypeNode = new RiskMeasureTypeNode();
        BeanUtils.copyProperties(measureType, riskMeasureTypeNode);
        // 统计子类型数量,有子分类不允许删除
        int countChild = riskMeasureTypeMapper.countAllByParentId(measureType.getId());
        riskMeasureTypeNode.setExistChild(countChild > 0);
        // 该类型已有具体措施，不允许删除(lastEvaluationIds：所有风险点的最后一次评估)
        if (!CollectionUtils.isEmpty(lastEvaluationIds)) {
            int countUsed = riskPointEvaluationDetailDao.countByMethodId(measureType.getId(), lastEvaluationIds);
            riskMeasureTypeNode.setHadBind(countUsed > 0);
        }
        return riskMeasureTypeNode;
    }

    public String findNameById(Long id) {
        return id == null ? null : riskMeasureTypeMapper.findNameById(id);
    }


    public Integer getMaxTypeLevel() {
        return riskMeasureTypeMapper.getMaxTypeLevel(Context.getCompanyCode(), Context.getCurrentTenantId());
    }

    public List<String> getNamesByTypeLevel(Integer typeLevel) {
        return riskMeasureTypeMapper.getNamesByTypeLevel(typeLevel, Context.getCompanyCode(), Context.getCurrentTenantId());
    }

}
